#include "stdafx.h"

#include <iostream>
#include <ctime>
#include <exception>

#include "boost/tokenizer.hpp"
#include "boost/filesystem/operations.hpp"
#include "boost/algorithm/string.hpp"

#include "Application.h"
#include "Searcher.h"
#include "IndexMap.h"

Application::Application(int length, const char* parameters[])
{
	init(length, parameters);
}

void Application::init(int length, const char* parameters[])
{
	using namespace std;

	set<string>* tokens;
	string helpMessage("To see help enter \"--help\" or \"-h\". ");

	if (length == 1)
	{
		cout 
			<< "To work with the program enter the startup parameters. " 
			<< endl 
			<< helpMessage 
			<< endl;
		return;
	}
	string pathToDir(parameters[1]);	
	
	if (length == 2)
	{
		if((pathToDir == "-help") || (pathToDir == "-h"))
		{
			showHelp();
		} 
		else 
		{
			cout 
				<< "Command \"" << pathToDir << "\" is unsupported. " 
				<< endl
				<< helpMessage 
				<< endl;
		}

		return;
	}
	
	string inputString(parameters[2]);

	boost::algorithm::to_lower(inputString);

	if (length == 3)
	{
		using namespace boost::filesystem3;
		path dirPath(pathToDir);
		
		if (!exists(dirPath))
		{
			cout 
				<< "Path\"" << pathToDir << "\" does not exist. " 
				<< endl 
				<< helpMessage 
				<< endl;
			return;
		}

		if (!is_directory(dirPath))
		{
			cout 
				<< "Path\"" << pathToDir << "\" is not of a directory. " 
				<< endl  
				<< helpMessage 
				<< endl;
			return;
		}

		if((inputString == "--indexing") || (inputString == "-i"))
		{
			prepareToSearch(pathToDir);
			return;
		}

		bool containsLeftTag = (inputString.find("<") != string::npos);
		bool containsRightTag = (inputString.find(">") != string::npos);
		
		if (containsLeftTag || containsRightTag)
		{
			cout 
				<< "Search string contains illegal characters: "
				<< (containsLeftTag ? "<" : "") << (containsRightTag ? ">" : "") 
				<< endl
				<< helpMessage 
				<< endl;
			return;
		}

		int size = inputString.size();
		if (!(size >= 4 && size <= 200))
		{
			cout 
				<< "Search string must be from 4 to 200 characters long." << endl 
				<< helpMessage << endl;
			return;
		}

		tokens = tokenize(inputString);
		if (tokens->size() == 0)
		{
			cout 
				<< "There are not words for search. " << endl
				<< helpMessage << endl;
			return;
		}
		startSearch(pathToDir, *tokens);
		delete(tokens);
		return;
	}

	cout << "Too many arguments. " << endl << helpMessage << endl;
}

void Application::prepareToSearch(std::string& pathToDir)
{
	try 
	{
		IndexMap::create(pathToDir);
	}
	catch(std::exception& ex)
	{
		std::cout << ex.what();
	}
}
void Application::startSearch(std::string& pathToDir, std::set<std::string>& strings)
{
	try 
	{
		Searcher s;
		s.search(strings, pathToDir);
	}
	catch(std::exception& ex)
	{
		std::cout << ex.what();
	}
}

void Application::showHelp()
{
	using namespace std;
	cout 
		<< "The program is designed to search words in files in the directory" 
		<< endl	<< "and sub-directions."
		<< endl << "There are 2 phase of work: preparation and main." << endl
		<< "Preparation phase is designed to prepare a directory for search;" << endl
		<< "Main phase is designed to do search." << endl << endl
		<< "To run preparaion phase enter: <path to directory> -i | --indexing." <<endl
		<< "Example: c:\\dir1 -i." << endl << endl
		<< "To run main phase enter: <path to directory> \"word1[ word2 word3 ...]\"." << endl
		<< "Example: c:\\dir1 \"earth map\"." << endl
		<< "Note: length of word set must be between 4 and 200." << endl << endl
		<< "To show help enter: -h | --help" << endl;
}

std::set<std::string>* Application::tokenize(std::string& inputString)
{
	using namespace std;

	set<string>* words = new set<string>();

	boost::char_separator<char> sep(" ");
	boost::tokenizer<boost::char_separator<char> > tokens(inputString, sep);

	set<string>::iterator iter;

	iter = words->begin();

	boost::tokenizer<boost::char_separator<char> >::iterator beg;

	for(beg = tokens.begin(); beg != tokens.end(); beg++)	
	{
		string token = *beg;
		
		if (token != "") 
		{
			iter = words->insert(iter, token);
		}
	}
	return words;
}